﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;


public class CameraGizmos : MonoBehaviour
{
#if UNITY_EDITOR
    [SerializeField]
    Camera mCamera;
    [SerializeField]
    Transform _camTrans;
    Plane[] cameraPlanes = new Plane[6];
    //边沿线上的四角坐标
    public Vector3[] RayCorners = new Vector3[4];
    //边沿线和平面相交的四角坐标
    Vector3[] PlaneCorners = new Vector3[4];
    //屏幕外宽，高范围
    [SerializeField]
    private int outWidth = 20;
    [SerializeField]
    private int outHeight = 20;
    //正交视角，倾斜角度的长度偏差了10
    private float maxOffHeight = 10;
    private void Awake()
    {
        mCamera = GetComponent<Camera>();
        _camTrans = transform;
    }


    private void OnDrawGizmos()
    {
        if (mCamera == null) return;

        float dist =  _camTrans.position.y;
        OnDrawAllView();
        if (!mCamera.orthographic)
        {
            //OnDrawConeOfCameraVision();
           // RayCorners = GetFOVCorners2(dist);
            //再计算窗口沿视线到地面的长度
            var z0 = Mathf.Abs(dist) / Mathf.Cos((90-_camTrans.rotation.eulerAngles.x + mCamera.fieldOfView * 0.5f) * Mathf.Deg2Rad);
            var z1 = Mathf.Abs(dist) / Mathf.Cos((90-_camTrans.rotation.eulerAngles.x - mCamera.fieldOfView * 0.5f) * Mathf.Deg2Rad);

            RayCorners[0] = Screen2World(new Vector3(0, 0, z1));//左下
            RayCorners[1] = Screen2World(new Vector3(0, 1, z0));//左上
            RayCorners[2] = Screen2World(new Vector3(1, 1, z0));//右上
            RayCorners[3] = Screen2World(new Vector3(1, 0, z1));//右下
            Gizmos.color = Color.green;
            for (int i = 0; i < RayCorners.Length; i++)
            {
                var pos = RayCorners[i];
                Gizmos.DrawWireCube(pos, Vector3.one * 5);

            }
            //OnDrawFarView();
            OnDrawOrthographicSpawnMonsterArea(_camTrans.rotation.eulerAngles.x, dist);
        }
        else
        {
            Gizmos.color = Color.green;

            //先计算平面窗口顶点的世界坐标
            var UpperLeft = Screen2World(new Vector3(0, 1, 0));
            var UpperRight = Screen2World(new Vector3(1, 1, 0));
            var LowerLeft = Screen2World(new Vector3(0, 0, 0)); 
            var LowerRight = Screen2World(new Vector3(1, 0, 0));

            //再计算窗口沿视线到地面的长度
            var z0 = Mathf.Abs(UpperLeft.y) / Mathf.Sin(_camTrans.rotation.eulerAngles.x * Mathf.Deg2Rad);
            var z1 = Mathf.Abs(UpperRight.y) / Mathf.Sin(_camTrans.rotation.eulerAngles.x * Mathf.Deg2Rad);
            var z2 = Mathf.Abs(LowerLeft.y) / Mathf.Sin(_camTrans.rotation.eulerAngles.x * Mathf.Deg2Rad);
            var z3 = Mathf.Abs(LowerRight.y) / Mathf.Sin(_camTrans.rotation.eulerAngles.x * Mathf.Deg2Rad);
            RayCorners[0] = Screen2World(new Vector3(0, 0, z2));
            RayCorners[1] = Screen2World(new Vector3(0, 1, z0));
            RayCorners[2] = Screen2World(new Vector3(1, 1, z1));
            RayCorners[3] = Screen2World(new Vector3(1, 0, z3));

            for (int i = 0; i < RayCorners.Length; i++)
            {
                var pos = RayCorners[i];
                Gizmos.DrawWireCube(pos, Vector3.one * 5);
            }
            Gizmos.color = Color.white;
            //OnDrawFarView();
            OnDrawOrthographicSpawnMonsterArea(_camTrans.rotation.eulerAngles.x, dist);
        }

        Debug.DrawLine(_camTrans.position,new Vector3(_camTrans.position.x,0, _camTrans.position.z), Color.green); 
    }
    private  Vector3 Screen2World(Vector3 viewportPos)
    {
        var worldPos = Camera.main.ViewportToWorldPoint(viewportPos);
        return worldPos;
    }
    public bool CheckBoundIsInCamera(Bounds bound, Camera camera)
    {
        GeometryUtility.CalculateFrustumPlanes(camera, cameraPlanes);
        return GeometryUtility.TestPlanesAABB(cameraPlanes, bound);
    }


    void OnDrawAllView()
    {
        Gizmos.color = Color.yellow;
        Matrix4x4 temp = Gizmos.matrix;
        Gizmos.matrix = Matrix4x4.TRS(transform.position, transform.rotation, Vector3.one);
        if (mCamera.orthographic)
        {
            float z = mCamera.farClipPlane - mCamera.nearClipPlane;
            float center = (mCamera.farClipPlane + mCamera.nearClipPlane) * 0.5f;
            Gizmos.DrawWireCube(new Vector3(0, 0, center), new Vector3(mCamera.orthographicSize * 2 * mCamera.aspect, mCamera.orthographicSize * 2, z));
        }
        else
        {
            Gizmos.DrawFrustum(Vector3.zero, mCamera.fieldOfView, mCamera.farClipPlane, mCamera.nearClipPlane, mCamera.aspect);
        }
        Gizmos.matrix = temp;
    }

    /// <summary>
    /// 绘制较远的视口
    /// </summary>
    void OnDrawFarView()
    {

        // for debugging
        Debug.DrawLine(RayCorners[1], RayCorners[2], Color.yellow); // UpperLeft -> UpperRight
        Debug.DrawLine(RayCorners[2], RayCorners[3], Color.yellow); // UpperRight -> LowerRight
        Debug.DrawLine(RayCorners[3], RayCorners[0], Color.yellow); // LowerRight -> LowerLeft
        Debug.DrawLine(RayCorners[0], RayCorners[1], Color.yellow); // LowerLeft -> UpperLeft


        //中心线
        Vector3 vecStart = _camTrans.transform.position;
        Vector3 vecEnd = vecStart;
        vecEnd += _camTrans.forward * mCamera.farClipPlane;
        Debug.DrawLine(vecStart, vecEnd, Color.red);
        Debug.DrawLine(vecStart, new Vector3(vecStart.x,0, vecStart.z), Color.yellow);
    }

    /// <summary>
    /// 绘制较近的视口
    /// </summary>
    void OnDrawNearView()
    {
        Vector3[] corners = GetCorners(mCamera.nearClipPlane);

        // for debugging
        Debug.DrawLine(corners[0], corners[1], Color.red);//左上-右上
        Debug.DrawLine(corners[1], corners[3], Color.red);//右上-右下
        Debug.DrawLine(corners[3], corners[2], Color.red);//右下-左下
        Debug.DrawLine(corners[2], corners[0], Color.red);//左下-左上
    }

    /// <summary>
    /// 绘制 camera 的 FOV
    /// </summary>
    void OnDrawFOV()
    {
        float _farDistance = mCamera.farClipPlane;
        float halfFOV = (mCamera.fieldOfView * 0.5f) * Mathf.Deg2Rad;//一半fov
        float halfHeight = _farDistance * Mathf.Tan(halfFOV);//distance距离位置，相机视口高度的一半

        //起点
        Vector3 vecStart = _camTrans.position;

        //上中
        Vector3 vecUpCenter = vecStart;
        vecUpCenter.y -= halfHeight;
        vecUpCenter.z += _farDistance;

        //下中
        Vector3 vecBottomCenter = vecStart;
        vecBottomCenter.y += halfHeight;
        vecBottomCenter.z += _farDistance;

        Debug.DrawLine(vecStart, vecUpCenter, Color.blue);
        Debug.DrawLine(vecStart, vecBottomCenter, Color.blue);
    }

    /// <summary>
    /// 绘制 camera 的视锥 边沿
    /// </summary>
    void OnDrawConeOfCameraVision()
    {
        Vector3[] corners = GetCorners(mCamera.farClipPlane);

        // for debugging
        Debug.DrawLine(_camTrans.position, corners[1], Color.green); // UpperLeft -> UpperRight
        Debug.DrawLine(_camTrans.position, corners[3], Color.green); // UpperRight -> LowerRight
        Debug.DrawLine(_camTrans.position, corners[2], Color.green); // LowerRight -> LowerLeft
        Debug.DrawLine(_camTrans.position, corners[0], Color.green); // LowerLeft -> UpperLeft
    }
    /// <summary>
    /// 绘制垂直地面90度的范围产怪区域
    /// </summary>
    void OnDrawFOV90SpawnMonsterArea(float angle, float dist)
    {
        RayCorners = GetFOVCorners2(dist);

        int offX = 20;
        int offZ = 20;
        var UpperLeft = new Vector3(RayCorners[1].x - offX, RayCorners[1].y, RayCorners[1].z + offZ);
        var UpperRight = new Vector3(RayCorners[2].x + offX, RayCorners[2].y, RayCorners[2].z + offZ);
        var LowerLeft = new Vector3(RayCorners[0].x - offX, RayCorners[0].y, RayCorners[0].z - offZ);
        var LowerRight = new Vector3(RayCorners[3].x + offX, RayCorners[3].y, RayCorners[3].z - offZ);
        //外矩形
        Debug.DrawLine(UpperLeft, UpperRight, Color.red); // UpperLeft -> UpperRight
        Debug.DrawLine(UpperRight, LowerRight, Color.red); // UpperRight -> LowerRight
        Debug.DrawLine(LowerRight, LowerLeft, Color.red); // LowerRight -> LowerLeft
        Debug.DrawLine(LowerLeft, UpperLeft, Color.red); // LowerLeft -> UpperLeft
        //内矩形
        Debug.DrawLine(RayCorners[1], RayCorners[2], Color.green); // UpperLeft -> UpperRight
        Debug.DrawLine(RayCorners[2], RayCorners[3], Color.green); // UpperRight -> LowerRight
        Debug.DrawLine(RayCorners[3], RayCorners[0], Color.green); // LowerRight -> LowerLeft
        Debug.DrawLine(RayCorners[0], RayCorners[1], Color.green); // LowerLeft -> UpperLeft
    }

    /// <summary>
    /// 平面上的产怪区域
    /// </summary>
    /// <param name="distance"></param>
    void OnDrawOrthographicSpawnMonsterArea(float angle,float dist)
    {
        int offX = outWidth;
        int offZ = outHeight;
        var UpperLeft = new Vector3(RayCorners[1].x - offX, RayCorners[1].y, RayCorners[1].z + offZ);
        var UpperRight = new Vector3(RayCorners[2].x + offX, RayCorners[2].y, RayCorners[2].z + offZ);
        var LowerLeft = new Vector3(RayCorners[0].x - offX, RayCorners[0].y, RayCorners[0].z - offZ);
        var LowerRight = new Vector3(RayCorners[3].x + offX, RayCorners[3].y, RayCorners[3].z - offZ);
        //外矩形
        Debug.DrawLine(UpperLeft, UpperRight, Color.red); // UpperLeft -> UpperRight
        Debug.DrawLine(UpperRight, LowerRight, Color.red); // UpperRight -> LowerRight
        Debug.DrawLine(LowerRight, LowerLeft, Color.red); // LowerRight -> LowerLeft
        Debug.DrawLine(LowerLeft, UpperLeft, Color.red); // LowerLeft -> UpperLeft
        //内矩形
        Debug.DrawLine(RayCorners[1], RayCorners[2], Color.green); // UpperLeft -> UpperRight
        Debug.DrawLine(RayCorners[2], RayCorners[3], Color.green); // UpperRight -> LowerRight
        Debug.DrawLine(RayCorners[3], RayCorners[0], Color.green); // LowerRight -> LowerLeft
        Debug.DrawLine(RayCorners[0], RayCorners[1], Color.green); // LowerLeft -> UpperLeft
    }

    //获取视锥视口四个角的坐标
    //参数 distance  视口距离
    Vector3[] GetCorners(float distance)
    {
        Vector3[] corners = new Vector3[4];
        if (mCamera == null || _camTrans == null) return corners;

        //fov为垂直视野  水平fov取决于视口的宽高比  以度为单位

        float halfFOV = (mCamera.fieldOfView * 0.5f) * Mathf.Deg2Rad;//一半fov
        float aspect = mCamera.aspect;//相机视口宽高比

        float height = distance * Mathf.Tan(halfFOV);//distance距离位置，相机视口高度的一半
        float width = height * aspect;//相机视口宽度的一半

        //左上
        corners[0] = _camTrans.position - (_camTrans.right * width);//相机坐标 - 视口宽的一半
        corners[0] += _camTrans.up * height;//+视口高的一半
        corners[0] += _camTrans.forward * distance;//+视口距离

        // 右上
        corners[1] = _camTrans.position + (_camTrans.right * width);//相机坐标 + 视口宽的一半
        corners[1] += _camTrans.up * height;//+视口高的一半
        corners[1] += _camTrans.forward * distance;//+视口距离

        // 左下
        corners[2] = _camTrans.position - (_camTrans.right * width);//相机坐标 - 视口宽的一半
        corners[2] -= _camTrans.up * height;//-视口高的一半
        corners[2] += _camTrans.forward * distance;//+视口距离

        // 右下
        corners[3] = _camTrans.position + (_camTrans.right * width);//相机坐标 + 视口宽的一半
        corners[3] -= _camTrans.up * height;//-视口高的一半
        corners[3] += _camTrans.forward * distance;//+视口距离



        return corners;
    }

#if UNITY_EDITOR
    static int mSizeFrame = -1;
    static System.Reflection.MethodInfo s_GetSizeOfMainGameView;
    static Vector2 mGameSize = Vector2.one;

    /// <summary>
    /// Size of the game view cannot be retrieved from Screen.width and Screen.height when the game view is hidden.
    /// </summary>

    public Vector2 screenSize
    {
        get
        {
            int frame = Time.frameCount;

            if (mSizeFrame != frame || !Application.isPlaying)
            {
                mSizeFrame = frame;

                if (s_GetSizeOfMainGameView == null)
                {
                    System.Type type = System.Type.GetType("UnityEditor.GameView,UnityEditor");
                    s_GetSizeOfMainGameView = type.GetMethod("GetSizeOfMainGameView",
                        System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
                }
                mGameSize = (Vector2)s_GetSizeOfMainGameView.Invoke(null, null);
            }
            return mGameSize;
        }
    }
#else
    /// <summary>
    /// Size of the game view cannot be retrieved from Screen.width and Screen.height when the game view is hidden.
    /// </summary>

    public Vector2 screenSize { get { return new Vector2(Screen.width, Screen.height); } }
#endif

    /// <summary>
    /// 第2种计算camera视锥内四个角落点坐标
    /// </summary>
    /// <param name="distance"></param>
    /// <returns></returns>
    private Vector3[] GetFOVCorners2(float distance)
    {
        Vector3[] frustumCorners = new Vector3[4];
        mCamera.CalculateFrustumCorners(new Rect(0, 0, 1, 1), distance, Camera.MonoOrStereoscopicEye.Mono, frustumCorners);
        for (int i = 0; i < 4; i++)
        {
            var pos = mCamera.transform.TransformPoint(frustumCorners[i]);
            frustumCorners[i] = pos;
        }

        return frustumCorners;
    }

#endif

}
